package lt.marsrutai.mobile.android.activity;

import java.math.BigDecimal;
import java.util.List;

import lt.marsrutai.mobile.android.R;
import lt.marsrutai.mobile.android.util.PreferenceUtils;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageButton;

import com.google.analytics.tracking.android.EasyTracker;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.MyLocationOverlay;
import com.google.android.maps.Overlay;

/**
 * Base map activity providing current location indicator with a compass
 * 
 * @author Justas
 */
public abstract class BaseMapActivity extends MapActivity {

    private static final int INIT_ZOOM_LEVEL = 16;
    
    protected MyLocationOverlay myLocationOverlay;
    protected MapView mapView;
    protected Button mapTypeButton;
    
    private boolean animateToCurrentLocation = true;
    private boolean satelliteSelected;
    
    public BaseMapActivity() {
    } 
    
    /**
     * 
     * @param animateToMyLocation
     *            Indicates whether map should be centered to my current
     *            location when first fix is acquired. Default -
     *            <code>true</code>.
     */
    public BaseMapActivity(boolean animateToMyLocation) {
        this.animateToCurrentLocation = animateToMyLocation;
    }
    
    @Override
    protected void onStart() {
        super.onStart();
        EasyTracker.getInstance().activityStart(this);
    }
    
    @Override
    protected void onStop() {
        super.onStop();        
        EasyTracker.getInstance().activityStop(this);
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        
        myLocationOverlay.enableCompass();
        myLocationOverlay.enableMyLocation();
    }
    
    @Override
    protected void onPause() {
        super.onPause();
        
        myLocationOverlay.disableCompass();
        myLocationOverlay.disableMyLocation();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        setupMapView();
    }

    protected void setupMapView() {
        setContentView(R.layout.map_layout);
        mapView = (MapView) findViewById(R.id.mapview);
        mapView.setBuiltInZoomControls(true);
        
        MapController mapController = mapView.getController();
        mapController.setZoom(INIT_ZOOM_LEVEL);
        
        List<Overlay> listOfOverlays = mapView.getOverlays();
        listOfOverlays.clear();
        
        // center map to my location 
        myLocationOverlay = new MyLocationOverlay(this, mapView);
        myLocationOverlay.runOnFirstFix(new Runnable() {

            public void run() {
                if (animateToCurrentLocation) {
                    animateToCurrentLocation();
                }
            }
        });
        listOfOverlays.add(myLocationOverlay);
        
        ImageButton current_location_button = (ImageButton) findViewById(R.id.button_current_location);
        current_location_button.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                animateToCurrentLocation();
            }
        });
        
        mapTypeButton = (Button) findViewById(R.id.button_map_type);
        satelliteSelected = PreferenceUtils.<Boolean>getPreferenceValue(this, PreferenceUtils.MAP_VIEW_TYPE_SATELLITE);
        updateMapType(satelliteSelected);
        mapTypeButton.setOnClickListener(new OnClickListener() {
            
            @Override
            public void onClick(View v) {
                satelliteSelected = !satelliteSelected;
                updateMapType(satelliteSelected);
            }
        });
    }

    /**
     * Update button text and save the preference
     * 
     * @param satelliteSelected
     */
    protected void updateMapType(boolean satelliteSelected) {
        mapView.setSatellite(satelliteSelected);
        mapTypeButton.setText(satelliteSelected ? R.string.map_type_map : R.string.map_type_satellite);
        PreferenceUtils.setBooleanPreferenceValue(this, PreferenceUtils.MAP_VIEW_TYPE_SATELLITE, satelliteSelected);
    }
    
    @Override
    protected boolean isRouteDisplayed() {
        return false;
    }
    
    /**
     * Centers the map to the current location
     */
    protected void animateToCurrentLocation() {
        GeoPoint currentLocation = myLocationOverlay.getMyLocation();
        
        if (currentLocation != null) {
            mapView.getController().animateTo(currentLocation);
        }
    }

    /**
     * Creates {@link GeoPoint} from latitude and longitude
     * 
     * @param latitude
     * @param longitude
     * @return
     */
    protected GeoPoint createGeoPoint(BigDecimal latitude, BigDecimal longitude) {
        return new GeoPoint(
                latitude.multiply(new BigDecimal(1e6)).intValue(), 
                longitude.multiply(new BigDecimal(1e6)).intValue());
    }
    
    /**
     * Zoom level is determined automatically in such a manner, that all the
     * provided items are visible in the screen.
     * 
     * @param items
     * @see http://stackoverflow.com/a/5242149
     */
    protected void zoomToItems(List<GeoPoint> items) {
        MapController mapController = mapView.getController();
        
        int minLat = Integer.MAX_VALUE;
        int maxLat = Integer.MIN_VALUE;
        int minLon = Integer.MAX_VALUE;
        int maxLon = Integer.MIN_VALUE;

        for (GeoPoint item : items) {

            int lat = item.getLatitudeE6();
            int lon = item.getLongitudeE6();

            maxLat = Math.max(lat, maxLat);
            minLat = Math.min(lat, minLat);
            maxLon = Math.max(lon, maxLon);
            minLon = Math.min(lon, minLon);
        }

        // factor is needed so that no points would appear to be too close to the screen edge
        double fitFactor = 1.5;
        mapController.zoomToSpan((int) (Math.abs(maxLat - minLat) * fitFactor), (int) (Math.abs(maxLon - minLon) * fitFactor));
        mapController.animateTo(new GeoPoint((maxLat + minLat) / 2, (maxLon + minLon) / 2));
    }

}
